const stringify = require('fast-json-stable-stringify');
import { v4 as uuid } from 'uuid';
import md5 from '@utils/md5';
type optionsType = {
    notNeedRequestIdList?: string[];
    // 需要用到url + params的作为key的映射形式,默认 true
    needUrlAndParamsKey?: boolean;
    // 如果needUrlAndParamsKey选项为true,则相同url 不同参数的key最大共存数目，默认5个；
    // 减少内容
    sameUrlMaxKeyNum?: number;
};
type dataType = Record<string, unknown>;

const requestUrlIdMap: Record<string, string> = {};
const sameUrlToKeyListMap: Record<string, string[]> = {};
const defaultSameUrlMaxKeyNum = 5;
const notShowErrorList = [91201];

const createRequestId = () => {
    const requestId = uuid() + '#' + Date.now() + '#';
    return requestId;
};

const getKeyByDataAndOptions = (url: string, data: dataType, options: optionsType) => {
    //json转字符串 得到稳定的一顺序值
    const dataStr = stringify(data);
    const dataMd5 = md5(dataStr);
    let key = url;
    //默认配置
    if (options.needUrlAndParamsKey + '' !== 'false') {
        key = `${url}#${dataMd5}`;
        if (!sameUrlToKeyListMap[url]) {
            sameUrlToKeyListMap[url] = [key];
        } else if (!sameUrlToKeyListMap[url].includes(key)) {
            if (sameUrlToKeyListMap[url].length < defaultSameUrlMaxKeyNum) {
                sameUrlToKeyListMap[url].push(key);
            } else {
                //剔除了最前面的那个key
                const deleteKeyName = sameUrlToKeyListMap[url][0];
                delete requestUrlIdMap[deleteKeyName];
                sameUrlToKeyListMap[url] = sameUrlToKeyListMap[url].slice(1);
                sameUrlToKeyListMap[url].push(key);
            }
        }
    }
    return key;
};

const idempotentFn = (axiosInstance, options: optionsType) => {
    const notNeedRequestIdList = options.notNeedRequestIdList || [];

    //请求拦截器
    axiosInstance.interceptors.request.use(
        function (config) {
            const url = config?.url || '';
            const data = config?.data || {};
            const key = getKeyByDataAndOptions(url, data, options);

            if (!requestUrlIdMap[key]) {
                requestUrlIdMap[key] = createRequestId();
            }
            // 默认需要requestId
            if (!notNeedRequestIdList.includes(url)) {
                config.headers = config.headers || {};
                config.headers = Object.assign(config.headers, { 'wx-request-id': requestUrlIdMap[key] });
            }
            return config;
        },
        // 以下function目前不清楚什么时候触发
        function (error) {
            const url = error?.url || '';
            const data = error?.data || {};
            const key = getKeyByDataAndOptions(url, data, options);
            requestUrlIdMap[key] = createRequestId();

            return Promise.reject(error);
        },
    );

    // 响应拦截器
    axiosInstance.interceptors.response.use(
        function (response) {
            try {
                // 2xx 范围内的状态码都会触发该函数,后端有了返回，不管是不是17000都走这里
                // 对响应数据做点什么
                const url = response?.config?.url || '';
                const data = JSON.parse(response.config?.data) || {};
                const key = getKeyByDataAndOptions(url, data, options);
                const returnCode = response?.data?.returnCode || 0;
                //91201
                if (!notShowErrorList.includes(returnCode)) {
                    requestUrlIdMap[key] = createRequestId();
                }
            } catch (e) {
                console.log(`未知错误: ${e}`);
            }

            return response;
        },
        function (error) {
            try {
                // 超出 2xx 范围的状态码都会触发该函数。
                // 对响应错误做点什
                const url = error?.config?.url || '';
                const data = JSON.parse(error.config?.data) || {};
                const key = getKeyByDataAndOptions(url, data, options);
                requestUrlIdMap[key] = createRequestId();
            } catch (e) {
                console.log(`未知错误: ${e}`);
            }
            return Promise.reject(error);
        },
    );

    return axiosInstance;
};

export default idempotentFn;
